""" A plane set encapsulates a set of planes.
There are two ways to present a set of planes.
First, a plane_subset object is organized as:
    ps = [subset1, subsect2, ...]
where
    subset1 = [plane11, plane12, ...].
Second, a plane_set_flattened object has two members:
    number_planes=[n1, n2, ...]
    planes=[plan11, plane12, ..., plane1m, plane21, plane22, ..., plane2n, ...]
Both ways have equivalent information.
Those methods that operating on plane_subset objects have the prefix PSS, 
and those methods on plane_set_flattened objects have the prefix PSF.
"""

def PSF_setd(number_planes, planes, distance) :
    ''' set distances of planes in a plane set, whose subsets are mingled 
    into one big list.

    number_planes: numbers of planes in the subsets of the plane set.
    planes: planes of all the subsets of the plane set, in a consistant oder 
        as the numbers of planes in the subsets.
    distance: [h0, h1, ...], origin-plane distances negated; can be negative or positive.
    '''
    index_start = 0
    for i, subset_n in enumerate(number_planes):
        index_end = index_start + subset_n
        for p in planes[index_start:index_end]: p.set_distance(distance[i])
        index_start = index_end    


def PSS_setd(planeset, distance):
    """ set distances of planes in a plane set, organized into subsets.

    planeset: a list of plane subset; a two-dimensional list.
    distance: a list of numbers; its length must equal the length of 'planeset',
        otherwise a ValueError is raised.
    """
    if(len(planeset) != len(distance)):
        raise ValueError("In particle_shape.ps_setd_mingled(): lenghth of \
            'planeset' mismatches length of 'distance'")
    for i, d in enumerate(distance):  
        for p in planeset[i]: p.set_distance(d) 


def PSS_flatten(planeset):
    """ flatten multiple plane sets into a single one.

    planeset:
        a list of plane subsets.
    returns:
    number_planes:
        a list of integers; numbers of planes of each plane subset.
    planes:
        a list of planes, in the order of the argument 'planeset'.
    """
    number_planes = []
    planes = []
    for ps in planeset:
        number_planes.append(len(ps))
        planes.extend(ps)
    return [number_planes, planes]


def PSS_flatten_family(plane_family, latt):
    """ return plane set from plane-family indices and lattice.

    plane_family: plane-family indices,
    latt: lattice parameters and point group of the crystal.
    returns: [number_planes, planes] with the default distance -1.0.
    """
    cc = latt.crystal_class
    pf_int = cc.plane_family(plane_family[0])   # a list of 3-number tuples
    number_planes = [ len(pf_int) ]
    for p in plane_family[1:]:
        if  not (p in pf_int) :
            pf = cc.plane_family(p)
            pf_int.extend( pf )
            number_planes.append( len(pf) )
        else:
            print("Duplicate plane family found:", p)
    planes = [latt.geometric_plane(p) for p in pf_int]
    return [number_planes, planes]

